﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PaceR.Core.Interfaces.Conditionals;
using PaceR.Core.Interfaces.Validation;
using PaceR.Core.Interfaces.PatternMatching;
using PaceR.Core.Utilities;

namespace PaceR.Core.Logic
{
    //Example
    /*
    public class MyTest
    {
        public MyTest()
        {
            var rule = SimpleLogicRule.Define().If<string, int>(
                SimpleLogicTest<string>.StartTest("hello").IsNotDefault()
                    .And().Test(4).IsLessThan(13)
                    .Or().Test(7).IsWithinRange(2, 67).IsTrue(),
                //then
                s => s.Length,
                //s equals
                "turkey");
        }
    }*/

    public class SimpleLogicTest<T> : IConditionTest, IConditionTest<T>, IConditionConstraint<T>
    {
        protected T testableValue;

        /// <summary>
        /// non-public constructor, force use of StartTest static method
        /// </summary> 
        protected SimpleLogicTest()
        { }

        public virtual IConditionTestable PreviousTest { get; set; }
        public virtual IConditionTestable NextTest { get; set; }
        public virtual BooleanOperators ConstraintConditional { get; set; }
        public virtual Func<T, bool> Assertion { get; set; }

        public static IConditionTest<T> TestValue(T testableValue)
        {
            return new SimpleLogicTest<T>() { testableValue = testableValue };
        }

        public virtual IConditionTest<T1> Test<T1>(T1 testableValue)
        {
            var fieldValidator = new SimpleLogicTest<T1>();

            NextTest = fieldValidator;
            return fieldValidator as IConditionTest<T1>;
        }

        public virtual bool RunTest()
        {
            bool success = Assertion(testableValue);
            if (success)
            {
                if (NextTest != null) return NextTest.RunTest();
            }
            else
            {
                if (NextTest != null && NextTest.ConstraintConditional == BooleanOperators.OR)
                    return NextTest.RunTest();
            }
            return success;
        }

        public virtual IConditionConstraint<T> IsDefault()
        {
            Assertion = v => EqualityComparer<T>.Default.Equals(v, default(T));
            return this;
        }

        public virtual IConditionConstraint<T> IsNotDefault()
        {
            Assertion = v => !EqualityComparer<T>.Default.Equals(v, default(T))
                && !string.IsNullOrEmpty(v.ToString().Trim());
            return this;
        }

        public virtual IConditionConstraint<T> Equals(T testParam)
        {
            Assertion = v => EqualityComparer<T>.Default.Equals(v, testParam);
            return this;
        }

        public virtual IConditionConstraint<T> DoesNotEqual(T testParam)
        {
            Assertion = v => !EqualityComparer<T>.Default.Equals(v, testParam);
            return this;
        }

        public virtual IConditionConstraint<T> IsGreaterThan(T testParam)
        {
            Assertion = v => Comparer<T>.Default.Compare(v, testParam) > 0;
            return this;
        }

        public virtual IConditionConstraint<T> IsLessThan(T testParam)
        {
            Assertion = v => Comparer<T>.Default.Compare(v, testParam) < 0;
            return this;
        }

        public virtual IConditionConstraint<T> IsWithinRange(T testParam1, T testParam2)
        {
            Assertion = v => Comparer<T>.Default.Compare(v, testParam1) >= 0
                && Comparer<T>.Default.Compare(v, testParam2) <= 0;
            return this;
        }

        public virtual IConditionConstraint<T> IsOutsideRange(T testParam1, T testParam2)
        {
            Assertion = v => Comparer<T>.Default.Compare(v, testParam1) > 0
                || Comparer<T>.Default.Compare(v, testParam2) > 0;
            return this;
        }

        public virtual IConditionConstraint<T> Matches(T testParam)
        {
            Assertion = v =>
            {
                IPatternMatcher<T> matcher = PatternMatchFactoryUtil.Factory.GetPatternMatcher(testParam);
                return matcher.Match(v);
            };
            return this;
        }

        public virtual IConditionConstraint<T> DoesNotMatch(T testParam)
        {
            Assertion = v =>
            {
                IPatternMatcher<T> matcher = PatternMatchFactoryUtil.Factory.GetPatternMatcher(testParam);
                return !matcher.Match(v);
            };
            return this;
        }

        public virtual IConditionTest And()
        {
            return this;
        }

        public virtual IConditionTest Or()
        {
            return this;
        }

        public virtual IConditionTestable IsTrue()
        {
            IConditionTestable firstTest = this;
            while (firstTest.PreviousTest != null)
                firstTest = firstTest.PreviousTest;
            //return
            return firstTest;
        }
    }
}
